package away3d.core.base ;


import away3d.animators.data.AnimationBase ;
import away3d.animators.data.AnimationStateBase ;
import away3d.materials.MaterialBase ;
import away3d.entities.Entity ;
import away3d.entities.Mesh ;
import flash.display3D.Context3D ;
import flash.display3D.IndexBuffer3D ;
import flash.display3D.VertexBuffer3D ;
import flash.geom.Matrix3D ;



/**
 * SubMesh wraps a SubGeometry as a scene graph instantiation. A SubMesh is owned by a Mesh object.
 *
 * @see away3d.core.base.SubGeometry
 * @see away3d.scenegraph.Mesh
 */
class SubMesh implements IRenderable
{
    
    
    public var _material        : MaterialBase ;
    private var _parentMesh     : Mesh ;
    private var _subGeometry    : SubGeometry ;
    public var _index           : Int  ;
    
    
    
    /**
     * Creates a new SubMesh object
     * @param subGeometry The SubGeometry object which provides the geometry data for this SubMesh.
     * @param parentMesh The Mesh object to which this SubMesh belongs.
     * @param material An optional material used to render this SubMesh.
     */
    public function new( subGeometry : SubGeometry, parentMesh : Mesh, ?material : MaterialBase = null )
    {
        
        _parentMesh     = parentMesh ;
        _subGeometry    = subGeometry ;
        this.material   = material ;
        
    }
    
    
    public var sourceEntity( get_sourceEntity, null ) : Entity ;
    
    
    /**
     * The entity that that initially provided the IRenderable to the render pipeline ( ie: the owning Mesh object ).
     */
    private function get_sourceEntity() : Entity
    {
        
        return _parentMesh ;
        
    }
    
    
    public var subGeometry( get_subGeometry, set_subGeometry ) : SubGeometry ;
    
    
    /**
     * The SubGeometry object which provides the geometry data for this SubMesh.
     */
    private function get_subGeometry() : SubGeometry
    {
        
        return _subGeometry ;
        
    }
    
    
    private function set_subGeometry( value : SubGeometry )
    {
        
        _subGeometry = value ;
        return value;
        
    }
    
    
    public var material( get_material, set_material ) : MaterialBase ;
    
    
    /**
     * The material used to render the current SubMesh. If set to null, its parent Mesh's material will be used instead.
     */
    private function get_material() : MaterialBase
    {
        
        return _material || _parentMesh.material ;
        
    }
    
    
    private function set_material( value : MaterialBase ) : MaterialBase 
    {
        
        if( _material ) _material.removeOwner( this ) ;
        
        _material = value ;
        
        if( _material ) _material.addOwner( this ) ;
        
        return value ;
        
    }
    
    
    public var animation( get_animation, null ) : AnimationBase ;
    
    
    /**
     * The animation object which is used to transform the geometry.
     */
    private function get_animation() : AnimationBase
    {
        
        return _subGeometry.animation ;
        
    }
    
    
    public var zIndex( get_zIndex, null ) : Float ;
    
    
    /**
     * The distance of the SubMesh object to the view, used to sort per object.
     */
    private function get_zIndex() : Float
    {
        
        return _parentMesh.zIndex ;
        
    }
    
    
    public var sceneTransform( get_sceneTransform, null ) : Matrix3D ;
    
    
    /**
     * The scene transform object that transforms from model to world space.
     */
    private function get_sceneTransform() : Matrix3D
    {
        
        return _parentMesh.sceneTransform ;
        
    }
    
    
    public var inverseSceneTransform( get_inverseSceneTransform, null ) : Matrix3D ;
    
    
    /**
     * The inverse scene transform object that transforms from world to model space.
     */
    private function get_inverseSceneTransform() : Matrix3D
    {
        return _parentMesh.inverseSceneTransform ;
    }
    
    /**
     * Retrieves the VertexBuffer3D object that contains vertex positions.
     * @param context The Context3D for which we request the buffer
     * @return The VertexBuffer3D object that contains vertex positions.
     */
    public function getVertexBuffer( context : Context3D, contextIndex : uint ) : VertexBuffer3D
    {
        
        return _subGeometry.getVertexBuffer( context, contextIndex ) ;
        
    }
    
    
    /**
     * Retrieves the VertexBuffer3D object that contains vertex normals.
     * @param context The Context3D for which we request the buffer
     * @return The VertexBuffer3D object that contains vertex normals.
     */
    public function getVertexNormalBuffer( context : Context3D, contextIndex : Int ) : VertexBuffer3D
    {
        
        return _subGeometry.getVertexNormalBuffer( context, contextIndex ) ;
        
    }
    
    
    /**
     * Retrieves the VertexBuffer3D object that contains vertex tangents.
     * @param context The Context3D for which we request the buffer
     * @return The VertexBuffer3D object that contains vertex tangents.
     */
    public function getVertexTangentBuffer( context : Context3D, contextIndex : Int ) : VertexBuffer3D
    {
        
        return _subGeometry.getVertexTangentBuffer( context, contextIndex ) ;
        
    }
    
    
    /**
     * Retrieves the VertexBuffer3D object that contains texture coordinates.
     * @param context The Context3D for which we request the buffer
     * @return The VertexBuffer3D object that contains texture coordinates.
     */
    public function getUVBuffer( context : Context3D, contextIndex : Int ) : VertexBuffer3D
    {
        
        return _subGeometry.getUVBuffer( context, contextIndex ) ;
        
    }
    
    
    /**
     * Retrieves the VertexBuffer3D object that contains triangle indices.
     * @param context The Context3D for which we request the buffer
     * @return The VertexBuffer3D object that contains triangle indices.
     */
    public function getIndexBuffer( context : Context3D, contextIndex : Int ) : IndexBuffer3D
    {
        
        return _subGeometry.getIndexBuffer( context, contextIndex ) ;
        
    }
    
    
    public var modelViewProjection( get_modelViewProjection, null ) : Matrix3D ;
    
    
    /**
     * The model-view-projection ( MVP ) matrix used to transform from model to homogeneous projection space.
     */
    private function get_modelViewProjection() : Matrix3D
    {
        
        return _parentMesh.modelViewProjection ;
        
    }
    
    
    public var numTriangles( get_numTriangles, Bool ) : Int ;
    
    
    /**
     * The amount of triangles that make up this SubMesh.
     */
    private function get_numTriangles() : Int
    {
        
        return _subGeometry.numTriangles ;
        
    }
    
    
    public var animationState( get_animationState, null ) : AnimationState ;
    
    
    /**
     * The AnimationStateBase object that provides the state for the SubMesh's animation.
     */
    private function get_animationState() : AnimationStateBase
    {
        
        return _parentMesh._animationState ;
        
    }
    
    
    public var mouseEnabled( get_mouseEnabled, null ) : Bool ;
    
    
    /**
     * Indicates whether the SubMesh should trigger mouse events, and hence should be rendered for hit testing.
     */
    private function get_mouseEnabled() : Bool
    {
        
        return _parentMesh.mouseEnabled ;
        
    }
    
    
    public var mouseDetails( get_mouseDetails, null ) : Bool ;
    
    
    /**
     * Indicates whether the SubMesh needs to provide mouse event details, such as position and uv coordinates.
     */
    private function get_mouseDetails() : Bool
    {
        
        return _parentMesh.mouseDetails ;
        
    }
    
    
    public var castsShadows( get_castShadows, null ) : Bool ;
    
    
    private function get_castsShadows() : Bool
    {
        
        return _parentMesh.castsShadows ;
        
    }
    
    
    /**
     * A reference to the owning Mesh object
     *
     * @private
     */
    
    
    public var parentMesh( get_parentMesh, set_parentMesh ) : Mesh ;
    
    
    private function get_parentMesh() : Mesh
    {
        
        return _parentMesh ;
        
    }
    
    
    private function set_parentMesh( value : Mesh ) : Mesh
    {
        
        _parentMesh = value ;
        return value ;
        
    }
    
    
}